#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/epoll.h>
#include <sys/resource.h>
#include <pthread.h>

#define MAX_EPOLL_EVENTS 2000
#define MAX_ROOMS 100  // 根据需要调整

/* Function Declarations */

void process_client_request(int clientFD, char *buffer);
void * clearWaitingPlayer(void * args);
void * clearInactiveRooms(void *args) ;
void printAllRooms();
/* Global Variables */
int waiting = 0;
char waitingPlayerName[15];
int waitingFD = 0;

struct PreGame {
    int player1FD;
    int player2FD;
    char player1Name[15];
    char player2Name[15];
    int readiness;
} preGames[50];

struct Room {
    int roomID;
    int player1FD;
    int player2FD;
    char player1Name[15];
    char player2Name[15];
    int isActive; // 标记房间是否处于活跃状态
    int hasPassword;           // 房间是否有密码（1 = 有, 0 = 无）
    char password[20];         // 房间密码（如果有）
} rooms[MAX_ROOMS];
int currentRoomIndex = 0;
pthread_mutex_t roomLock = PTHREAD_MUTEX_INITIALIZER; 
struct GameSession {
    int player1FD;
    int player2FD;
    int player1Choice;
    int player2Choice;
    int active;
} gameSessions[200];

int currentPreGameIndex = 0;
int currentGameSessionIndex = 0;

/* Main Function */
int main(){
    int serverSocketFD;
    struct sockaddr_in serverAddr;
    char buffer[1024];
    int bytesRead;
    signal(SIGPIPE, SIG_IGN);
    signal(SIGCHLD, SIG_IGN);
    pthread_t cleanRoomThread;
    pthread_create(&cleanRoomThread, NULL, clearInactiveRooms, NULL);

    /* Create Socket */
    if((serverSocketFD = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        perror("Cannot create socket");
        exit(1);
    }
    
    /* Configure Server Address */
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8081);
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    
    /* Bind Socket */
    if(bind(serverSocketFD, (const struct sockaddr *)&serverAddr, sizeof(struct sockaddr_in)) == -1){
        perror("Cannot bind socket");
        exit(1);
    }
    
    /* Listen on Socket */
    if(listen(serverSocketFD, 10) == -1){
        perror("Listen failed");
        exit(1);
    }
    
    /* Set Server Socket to Non-Blocking */
    if(fcntl(serverSocketFD, F_SETFL, fcntl(serverSocketFD, F_GETFD, 0) | O_NONBLOCK) == -1){
        printf("Set non-blocking Error: %d\n", errno);
        exit(EXIT_FAILURE);
    }
    
    /* Initialize Epoll */
    int epollFD = epoll_create1(0);
    if(epollFD == -1){
        perror("Epoll create failed");
        exit(1);
    }
    
    struct epoll_event event;
    event.events = EPOLLIN | EPOLLET;
    event.data.fd = serverSocketFD;
    
    /* Add Server Socket to Epoll */
    if(epoll_ctl(epollFD, EPOLL_CTL_ADD, serverSocketFD, &event) == -1){
        perror("Epoll ctl failed");
        exit(1);
    }
    
    int currentFds = 1;
    struct epoll_event events[MAX_EPOLL_EVENTS];
    
    /* Server Loop */
    while(1){
        int readyFds = epoll_wait(epollFD, events, currentFds, -1);
        if(readyFds == -1){
            printf("Epoll wait error: %d\n", errno);
            exit(1);
        }
        int i=0;
        for( i = 0; i < readyFds; i++){
            if(events[i].data.fd == serverSocketFD && currentFds < MAX_EPOLL_EVENTS){
                struct sockaddr_in clientAddr;
                socklen_t addrLen = sizeof(struct sockaddr_in);
                int clientFD = accept(serverSocketFD, (struct sockaddr *)&clientAddr, &addrLen);
                if(clientFD == -1){
                    printf("Accept error: %d\n", errno);
                    continue;
                }
                printf("有客户端连接\n");
                
                /* Set Client Socket to Non-Blocking */
                if(fcntl(clientFD, F_SETFL, fcntl(clientFD, F_GETFD, 0) | O_NONBLOCK) == -1){
                    printf("Set non-blocking Error: %d\n", errno);
                    close(clientFD);
                    continue;
                }
                
                /* Add Client Socket to Epoll */
                event.events = EPOLLIN | EPOLLET;
                event.data.fd = clientFD;
                if(epoll_ctl(epollFD, EPOLL_CTL_ADD, clientFD, &event) == -1){
                    printf("Epoll ctl failed: %d\n", errno);
                    close(clientFD);
                    continue;
                }
                currentFds++;
                continue;		
            }
            
            /* Handle Client Requests */
            int clientFD = events[i].data.fd;
            memset(buffer, 0, sizeof(buffer));
            bytesRead = read(clientFD, buffer, sizeof(buffer));
            if(bytesRead <= 0){
                close(clientFD);
                epoll_ctl(epollFD, EPOLL_CTL_DEL, clientFD, NULL);
                currentFds--;
                continue;
            }
            printf("客户端请求:%s\n", buffer);
            process_client_request(clientFD, buffer);
        }
    }
}

/* Process Client Request */
void process_client_request(int clientFD, char *buffer){
    char requestType[512] = {0};
    char requestData[512] = {0};
    char playerName[15] = {0};
    int hasPassword = 0;
    char password[20] = {0};
    int roomID;
    char joinPlayerName[15] = {0};
    sscanf(buffer, "%s%s", requestType, requestData);
    
    if (strcmp(requestType, "GS") == 0) {
        printf("服务器：开始匹配玩家 %s\n", requestData);
        if (waiting == 0) {
            waiting = 1;
            waitingFD = clientFD;
            strcpy(waitingPlayerName, requestData);
            write(clientFD, "WT 0\r\n\r\n", 8);
            pthread_t clearThread;
            pthread_create(&clearThread, NULL, clearWaitingPlayer, NULL);
        } else {
            if (clientFD == waitingFD) {
                write(clientFD, "WT 0\r\n\r\n", 8);
                return;
            }

            // Initialize Pre-Game Session
            preGames[currentPreGameIndex].player1FD = waitingFD;
            preGames[currentPreGameIndex].player2FD = clientFD;
            strcpy(preGames[currentPreGameIndex].player1Name, waitingPlayerName);
            strcpy(preGames[currentPreGameIndex].player2Name, requestData);
            preGames[currentPreGameIndex].readiness = 0;

            printf("服务器：开始匹配玩家：%s 与 %s\n", preGames[currentPreGameIndex].player1Name, preGames[currentPreGameIndex].player2Name);

            // Notify Both Players
            char response[128];
            sprintf(response, "PG %d\r\n\r\n", currentPreGameIndex);
            write(waitingFD, response, sizeof(response));
            write(clientFD, response, sizeof(response));
            printf("服务器：游戏会话 %d 开始，玩家 %s 与 %s\n", currentPreGameIndex, preGames[currentPreGameIndex].player1Name, preGames[currentPreGameIndex].player2Name);
            // Initialize Game Session
            gameSessions[currentGameSessionIndex].player1FD = preGames[currentPreGameIndex].player1FD;
            gameSessions[currentGameSessionIndex].player2FD = preGames[currentPreGameIndex].player2FD;
            gameSessions[currentGameSessionIndex].player1Choice = 0;
            gameSessions[currentGameSessionIndex].player2Choice = 0;
            gameSessions[currentGameSessionIndex].active = 1;
            currentGameSessionIndex = (currentGameSessionIndex == 199) ? 0 : currentGameSessionIndex + 1;
            currentPreGameIndex = (currentPreGameIndex == 49) ? 0 : currentPreGameIndex + 1;
        }
    } else if (strcmp(requestType, "RD") == 0) {
        int preGameIndex = atoi(requestData);
        preGames[preGameIndex].readiness += 1;
        printf("服务器：玩家 %s 准备好，等待另一方\n", preGames[preGameIndex].player2Name);

        if (preGames[preGameIndex].readiness == 2) {
            usleep(200000);  // 延时
            printf("服务器：双方准备就绪，游戏开始\n");
            char response[128];
            sprintf(response, "SG %d %s\r\n\r\n", preGameIndex, preGames[preGameIndex].player2Name);
            write(preGames[preGameIndex].player1FD, response, strlen(response));
            sprintf(response, "SG %d %s\r\n\r\n", preGameIndex, preGames[preGameIndex].player1Name);
            write(preGames[preGameIndex].player2FD, response, strlen(response));
        }
    }else if(strcmp(requestType, "DI") == 0){
        int sessionNumber = atoi(requestData);
        if(gameSessions[sessionNumber].active == 1){
            gameSessions[sessionNumber].active = 0;
            if(gameSessions[sessionNumber].player1FD != clientFD){
                write(gameSessions[sessionNumber].player1FD, "WI 0\r\n\r\n", 8);
            } else {
                write(gameSessions[sessionNumber].player2FD, "WI 0\r\n\r\n", 8);
            }
        }
    }else if(strcmp(requestType, "DQ") == 0){
        int sessionNumber = atoi(requestData);
        if(rooms[sessionNumber].isActive == 1){
            rooms[sessionNumber].isActive = 0;
            if(rooms[sessionNumber].player1FD != clientFD){
                write(rooms[sessionNumber].player1FD, "WI 0\r\n\r\n", 8);
            } else {
                write(rooms[sessionNumber].player2FD, "WI 0\r\n\r\n", 8);
            }
        }
    }else if(strcmp(requestType, "AL") == 0){
        int sessionNumber = atoi(requestData);
        char response[128];
        sprintf(response, "CD %d\r\n\r\n", 10);
        write(clientFD, response, sizeof(response));
    }
    if(strcmp(requestType, "CREATE_ROOM") == 0){
        sscanf(buffer, "%s %s %d %[^\n]", requestType, playerName, &hasPassword, password);
    
        pthread_mutex_lock(&roomLock);
        if(currentRoomIndex >= MAX_ROOMS){
            write(clientFD, "ERROR Max rooms reached\r\n\r\n", 26);
            pthread_mutex_unlock(&roomLock);
            return;
        }
        
        rooms[currentRoomIndex].roomID = currentRoomIndex;
        rooms[currentRoomIndex].player1FD = clientFD;
        strncpy(rooms[currentRoomIndex].player1Name, playerName, 14);
        rooms[currentRoomIndex].player1Name[14] = '\0'; // 确保字符串结束
        rooms[currentRoomIndex].player2FD = -1; // 暂无第二位玩家
        rooms[currentRoomIndex].isActive = 1;
        rooms[currentRoomIndex].hasPassword = hasPassword;
        if(hasPassword){
            strncpy(rooms[currentRoomIndex].password, password, 19);
            rooms[currentRoomIndex].password[19] = '\0';
        } else {
            rooms[currentRoomIndex].password[0] = '\0'; // 无密码时清空密码字段
        }
        
        // 打印房间创建信息
        if(hasPassword){
            printf("服务器: 创建房间成功，房间ID: %d，玩家1: %s (FD: %d)，有密码\n", 
                   rooms[currentRoomIndex].roomID, 
                   rooms[currentRoomIndex].player1Name, 
                   rooms[currentRoomIndex].player1FD);
        } else {
            printf("服务器: 创建房间成功，房间ID: %d，玩家1: %s (FD: %d)，无密码\n", 
                   rooms[currentRoomIndex].roomID, 
                   rooms[currentRoomIndex].player1Name, 
                   rooms[currentRoomIndex].player1FD);
        }
        
        // 通知客户端房间创建成功，并返回房间ID
        char response[128];
        sprintf(response, "ROOM_CREATED %d\r\n\r\n", rooms[currentRoomIndex].roomID);
        write(clientFD, response, strlen(response));
        
        currentRoomIndex++;
        pthread_mutex_unlock(&roomLock);
    }else if(strcmp(requestType, "JOIN_ROOM") == 0){
        
    sscanf(buffer, "%s %d %s %[^\n]", requestType, &roomID, joinPlayerName, password);
        
        pthread_mutex_lock(&roomLock);
        
        if(roomID < 0 || roomID >= currentRoomIndex || rooms[roomID].isActive == 0){
            write(clientFD, "ERROR Invalid room ID\r\n\r\n", 25);
            pthread_mutex_unlock(&roomLock);
            return;
        }
        if(rooms[roomID].player2FD != -1){
            write(clientFD, "ERROR Room is full\r\n\r\n", 22);
            pthread_mutex_unlock(&roomLock);
            return;
        }
        
        // 检查密码
        if(rooms[roomID].hasPassword){
            if(strcmp(rooms[roomID].password, password) != 0){
                write(clientFD, "ERROR Incorrect password\r\n\r\n", 27);
                pthread_mutex_unlock(&roomLock);
                return;
            }
        }
        
        rooms[roomID].player2FD = clientFD;
        strncpy(rooms[roomID].player2Name, joinPlayerName, 14);
        rooms[roomID].player2Name[14] = '\0';
        
        // 打印玩家加入房间信息
        if(rooms[roomID].hasPassword){
            printf("服务器: 玩家2加入房间ID: %d，玩家2: %s (FD: %d)，房间有密码\n", 
                   rooms[roomID].roomID, 
                   rooms[roomID].player2Name, 
                   rooms[roomID].player2FD);
        } else {
            printf("服务器: 玩家2加入房间ID: %d，玩家2: %s (FD: %d)，房间无密码\n", 
                   rooms[roomID].roomID, 
                   rooms[roomID].player2Name, 
                   rooms[roomID].player2FD);
        }
        
        // 通知两个玩家游戏开始
        char response1[128], response2[128];
        sprintf(response1, "GAME_START %d %s\r\n\r\n", rooms[roomID].roomID, rooms[roomID].player2Name);
        sprintf(response2, "GAME_START %d %s\r\n\r\n", rooms[roomID].roomID, rooms[roomID].player1Name);
        write(rooms[roomID].player1FD, response1, strlen(response1));
        write(clientFD, response2, strlen(response2));
        
        pthread_mutex_unlock(&roomLock);
    
}else if(strcmp(requestType, "LIST_ROOMS") == 0){
    pthread_mutex_lock(&roomLock);
    char response[4096] = "ROOM_LIST\n";
    for(int i = 0; i < currentRoomIndex; i++){
        if(rooms[i].isActive && rooms[i].player2FD == -1){
            char roomInfo[100];
            sprintf(roomInfo, "Room ID: %d, Host: %s, Password: %s\n",
                    rooms[i].roomID,
                    rooms[i].player1Name,
                    rooms[i].hasPassword ? "Yes" : "No");
            strcat(response, roomInfo);
        }
    }
    printf("Sending room list to client: %s\n", response);
    strcat(response, "\r\n\r\n");
    write(clientFD, response, strlen(response));
    pthread_mutex_unlock(&roomLock);
}


}
void printAllRooms(){
    pthread_mutex_lock(&roomLock);
    printf("当前所有房间状态:\n");
    for(int i = 0; i < currentRoomIndex; i++){
        printf("房间ID: %d, 玩家1: %s (FD: %d), 玩家2: %s (FD: %d), 状态: %s, 有密码: %s\n",
               rooms[i].roomID,
               rooms[i].player1Name,
               rooms[i].player1FD,
               rooms[i].player2Name,
               rooms[i].player2FD,
               rooms[i].isActive ? "活跃" : "不活跃",
               rooms[i].hasPassword ? "是" : "否");
    }
    pthread_mutex_unlock(&roomLock);
}
// 定期清理房间
void * clearInactiveRooms(void *args) {
    while (1) {
        sleep(ROOM_INACTIVITY_TIMEOUT);  // 每10分钟检查一次
        pthread_mutex_lock(&roomLock);
        
        for (int i = 0; i < currentRoomIndex; i++) {
            if (rooms[i].isActive == 1) {
                printf("服务器：房间 %d 超过不活跃时间，已被标记为不活跃\n", rooms[i].roomID);
                rooms[i].isActive = 0;
            }
        }

        pthread_mutex_unlock(&roomLock);
    }
}

// 定期清理等待超时玩家
void * clearWaitingPlayer(void * args){
    usleep(120000);
    waiting -= 1;
    if(waiting == 0){
        waitingFD = 0;
    }	
}

